/**
 * Copyright &copy; 2017-2020 <a href="http://www.fosung.com/">FosungFrame</a> All rights reserved.
 */
package com.fosung.frame.modules.sys.web;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.activiti.engine.impl.util.json.JSONArray;
import org.activiti.engine.impl.util.json.JSONObject;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.session.Session;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.fosung.frame.common.config.Global;
import com.fosung.frame.common.security.shiro.session.CacheSessionDAO;
import com.fosung.frame.common.security.shiro.session.SessionDAO;
import com.fosung.frame.common.servlet.ValidateCodeServlet;
import com.fosung.frame.common.utils.CacheUtils;
import com.fosung.frame.common.utils.CookieUtils;
import com.fosung.frame.common.utils.IdGen;
import com.fosung.frame.common.utils.StringUtils;
import com.fosung.frame.common.web.BaseController;
import com.fosung.frame.modules.sys.dao.OfficeDao;
import com.fosung.frame.modules.sys.dao.RoleDao;
import com.fosung.frame.modules.sys.dao.UserDao;
import com.fosung.frame.modules.sys.entity.Office;
import com.fosung.frame.modules.sys.entity.Role;
import com.fosung.frame.modules.sys.entity.User;
import com.fosung.frame.modules.sys.security.FormAuthenticationFilter;
import com.fosung.frame.modules.sys.security.SystemAuthorizingRealm;
import com.fosung.frame.modules.sys.security.UsernamePasswordToken;
import com.fosung.frame.modules.sys.service.OfficeService;
import com.fosung.frame.modules.sys.service.SystemService;
import com.fosung.frame.modules.sys.utils.HttpUtils;
import com.fosung.frame.modules.sys.utils.UserUtils;
import com.google.common.collect.Maps;

/**
 * 登录Controller
 * 
 * @author fosung
 * @version 2013-5-31
 */
@Controller
public class LoginController extends BaseController {

	@Autowired
	private SessionDAO sessionDAO;
	@Autowired
	private SystemService systemService;
	@Autowired
	private OfficeService officeService;
	@Autowired
	private RoleDao	roledao;
	@Autowired
	private UserDao userDao;
	@Autowired
	private OfficeDao officeDao;

	public static final String CLIENT_ID = Global.getConfig("clientId");
	public static final String CLIENT_SECRET = Global.getConfig("clientSecret");
	public static final String REDIRECT_HOST = Global.getConfig("redirectHost");
	public static final String REDIRECT_URI = Global.getConfig("redirect_uri");
	
	/**
	 * 跳转至登录页面
	 */
	@RequestMapping(value = "${adminPath}/logout", method = RequestMethod.GET)
	public String logout(HttpServletRequest request, HttpServletResponse response, Model model) {
		UserUtils.getSubject().logout();
		Cookie cookies[] = request.getCookies();  
	      if (cookies != null)  
	      {  
	    	  for (Cookie cookie : cookies) {
	    		  	/*cookie.setMaxAge(0);
					response.addCookie(cookie);*/
	    		  cookie.setValue(null);
                  cookie.setMaxAge(0);
                  cookie.setPath("/");
                  response.addCookie(cookie);
				}
	      }
//		CookieUtils.setCookie(response, "LOGINED", "false");
		return "redirect:"+REDIRECT_HOST+"/sso/logout";	
	}
	/**
	 * 跳转至登录页面
	 */
	@RequestMapping(value = "${adminPath}/login", method = RequestMethod.GET)
	public String login(HttpServletRequest request, HttpServletResponse response, Model model) {
		SystemAuthorizingRealm.Principal principal = UserUtils.getPrincipal();
		// 默认页签模式
		/*
		 * String tabmode = CookieUtils.getCookie(request, "tabmode"); if (tabmode == null){
		 * CookieUtils.setCookie(response, "tabmode", "1"); }
		 */
		if (logger.isDebugEnabled()) {
			logger.debug("login, active session size: {}", sessionDAO.getActiveSessions(false).size());
		}
		// 再次访问主页，则退出原账号（根据配置文件参数判断）
		if (Global.TRUE.equals(Global.getConfig("notAllowRefreshIndex"))) {
			CookieUtils.setCookie(response, "LOGINED", "false");
		}
		// 如果已经登录，则跳转到管理首页
		if (principal != null && !principal.isMobileLogin()) {
			return "redirect:" + adminPath;
		}
//		return "modules/sys/sysLogin3";
		return "redirect:"+REDIRECT_HOST+"/sso/oauth/authorize?client_id="+CLIENT_ID
				+ "&redirect_uri="+REDIRECT_URI+"/dcezb/admin/getCode&response_type=code";		
	}
	
	public String loginMe(HttpServletRequest request, HttpServletResponse response, Model model) {
		SystemAuthorizingRealm.Principal principal = UserUtils.getPrincipal();
		// 默认页签模式
		/*
		 * String tabmode = CookieUtils.getCookie(request, "tabmode"); if (tabmode == null){
		 * CookieUtils.setCookie(response, "tabmode", "1"); }
		 */
		if (logger.isDebugEnabled()) {
			logger.debug("login, active session size: {}", sessionDAO.getActiveSessions(false).size());
		}
		// 再次访问主页，则退出原账号（根据配置文件参数判断）
		if (Global.TRUE.equals(Global.getConfig("notAllowRefreshIndex"))) {
			CookieUtils.setCookie(response, "LOGINED", "false");
		}
		// 如果已经登录，则跳转到管理首页
		if (principal != null && !principal.isMobileLogin()) {
			return "redirect:" + adminPath;
		}
		return "modules/sys/sysLogin3";
		
	}
	
	
	/**
	 *  
	 * @param request
	 * @param response
	 * @param code  获取的code的值
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	@RequestMapping(value = "${adminPath}/getCode")
	public void getCode(HttpServletRequest request,HttpServletResponse response, String code, 
			Model model) throws UnsupportedEncodingException{
		Map<String, String> param = new HashMap<String, String>();
		param.put( "client_id", CLIENT_ID);
		param.put( "client_secret", CLIENT_SECRET);
		param.put( "grant_type", "authorization_code");
		param.put( "code", code);
		param.put( "redirect_uri", REDIRECT_URI+"/dcezb/admin/getCode");
		String url= REDIRECT_HOST+"/sso/oauth/token";
		String clientInfo=CLIENT_ID+":"+CLIENT_SECRET;
		String token = HttpUtils.post(url,param,clientInfo);
		
		
		/**用于存用户名**/
		String userName = "";
		
		//获取token值
		if(token!=null && !"".equals(token)){
			JSONObject tokenJSON = new JSONObject(token);
			String userauth = tokenJSON.optString("token_type")+" "+tokenJSON.optString("access_token");
	        String userStr=HttpUtils.getURLContent(REDIRECT_HOST+"/sso/user/principal","",userauth);
	        //获取用户信息
	        if(userStr!=null && !"".equals(userStr)){
	        	JSONObject userJSON = new JSONObject(userStr);
	        	/**
	        	 * 获取角色的信息，保存进角色的"clientId":"party-people-dcezb"的角色信息
	        	 * 角色和用户的关联 保存或者更新
	        	 * 
	        	 */
        		@SuppressWarnings("unused")
				List<Map<String,Object>>  roles=new ArrayList<Map<String,Object>>();
        		JSONArray ja = userJSON.optJSONArray("roles");
        		User userinfo = new User(); 
        		if (ja!=null) {
					for (int i = 0; i < ja.length(); i++) {
						JSONObject j = ja.getJSONObject(i);
						//获取"clientId":"party-people-dcezb"的jiaosexinxi
						String clientId=j.optString("clientId");
						if(clientId!=null && clientId.equals("party-people-dcezb")) {
							//保存组织信息
							String manageId=j.optString("manageId");
							if (manageId!=null) {
								Office office = officeService.get(manageId);
								if(office == null || "".equals(office.getId())){
									office =new Office();
									office.setId(manageId);
									office.setName(j.optString("manageName"));
									office.setCode(j.optString("manageCode"));
									officeDao.insert(office);
					        	}
								userinfo.setOffice(office);
							}
							//更新角色信息
							JSONArray  permissions =(JSONArray) j.get("permissions");
							String permissionName= (String) permissions.getJSONObject(0).get("permissionName");
							if (permissionName != null && !"".equals(permissionName)) {
								Role role =new Role();
								role.setName(permissionName);
								role=roledao.getByName(role);
								List<Role> rolelist=new ArrayList<Role>();
								rolelist.add(role);
								userinfo.setRoleList(rolelist);
							}
						}
						
					}
				}
	        	
	        	/**
	        	 *  保存更新用户的信息
	        	 */
	        	String ida=userJSON.optString("userId");
	        	User userinfo1=systemService.getUser(ida);
	        	if(userinfo1 == null || "".equals(userinfo1.getId())){
	        		userinfo.setId(ida);
	        		userinfo.setName(userJSON.optString("name"));
	        		userinfo.setLoginName(ida);
	        		userinfo.setPassword("02a3f0772fcca9f415adc990734b45c6f059c7d33ee28362c4852032");
	        		userinfo.setPhone(userJSON.optString("telephone"));
	        		userDao.insert(userinfo);
	        		userDao.deleteUserRole(userinfo);
	    			if (userinfo.getRoleList() != null && userinfo.getRoleList().size() > 0) {
	    				userDao.insertUserRole(userinfo);
	    			} 
	    			userinfo1=userinfo;
	        	}else{
	        		userinfo1.setRoleList(userinfo.getRoleList());
	        		userDao.deleteUserRole(userinfo1);
	        		if (userinfo.getRoleList() != null && userinfo.getRoleList().size() > 0) {
	    				userDao.insertUserRole(userinfo1);
	    			} 
	        	}
	        	userName = userinfo1.getLoginName();
//	        	model.addAttribute("userinfo", userinfo1);
	        }
        }
		
		try {
			SecurityUtils.getSubject().login(new UsernamePasswordToken(userName, "admin".toCharArray()));
			WebUtils.redirectToSavedRequest(request, response, adminPath);
		} catch (Exception e) {
			try {
				UserUtils.getSubject().logout();
				WebUtils.issueRedirect(request, response, REDIRECT_HOST
						+"/sso/oauth/authorize?client_id="+CLIENT_ID+"&redirect_uri="
						 +REDIRECT_URI+"/dcezb/admin/getCode&response_type=code");
			} catch (IOException e1) {
				e1.printStackTrace();
			}
		}
		
	}
	/**
	 * 登录验证，真正登录的POST请求由Filter完成
	 */
	@RequestMapping(value = "${adminPath}/login", method = RequestMethod.POST)
	public String loginFail(HttpServletRequest request, HttpServletResponse response, Model model) {
		SystemAuthorizingRealm.Principal principal = UserUtils.getPrincipal();
		// 如果已经登录，则跳转到管理首页
		if (principal != null) {
			return "redirect:" + adminPath;
		}
		
		String username = WebUtils.getCleanParam(request, FormAuthenticationFilter.DEFAULT_USERNAME_PARAM);
		boolean rememberMe = WebUtils.isTrue(request, FormAuthenticationFilter.DEFAULT_REMEMBER_ME_PARAM);
		boolean mobile = WebUtils.isTrue(request, FormAuthenticationFilter.DEFAULT_MOBILE_PARAM);
		String exception = (String) request.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);
		String message = (String) request.getAttribute(FormAuthenticationFilter.DEFAULT_MESSAGE_PARAM);

		if (StringUtils.isBlank(message) || StringUtils.equals(message, "null")) {
			message = "用户或密码错误, 请重试.";
		}

		model.addAttribute(FormAuthenticationFilter.DEFAULT_USERNAME_PARAM, username);
		model.addAttribute(FormAuthenticationFilter.DEFAULT_REMEMBER_ME_PARAM, rememberMe);
		model.addAttribute(FormAuthenticationFilter.DEFAULT_MOBILE_PARAM, mobile);
		model.addAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME, exception);
		model.addAttribute(FormAuthenticationFilter.DEFAULT_MESSAGE_PARAM, message);

		if (logger.isDebugEnabled()) {
			logger.debug("login fail, active session size: {}, message: {}, exception: {}",
					sessionDAO.getActiveSessions(false).size(), message, exception);
		}

		// 非授权异常，登录失败，验证码加1。
		if (!UnauthorizedException.class.getName().equals(exception)) {
			model.addAttribute("isValidateCodeLogin", isValidateCodeLogin(username, true, false));
		}

		// 验证失败清空验证码
		request.getSession().setAttribute(ValidateCodeServlet.VALIDATE_CODE, IdGen.uuid());

		// 如果是手机登录，则返回JSON字符串
		if (mobile) {
			return renderString(response, model);
		}

		return "modules/sys/sysLogin3";
	}

	/**
	 * 登录成功，进入管理首页
	 */
	@RequiresPermissions("user")
	@RequestMapping(value = "${adminPath}")
	public String index(HttpServletRequest request, HttpServletResponse response) {
		SystemAuthorizingRealm.Principal principal = UserUtils.getPrincipal();

		// 登录成功后，验证码计算器清零
		isValidateCodeLogin(principal.getLoginName(), false, true);

		if (logger.isDebugEnabled()) {
			logger.debug("show index, active session size: {}", sessionDAO.getActiveSessions(false).size());
		}

		// 如果已登录，再次访问主页，则退出原账号。
		if (Global.TRUE.equals(Global.getConfig("notAllowRefreshIndex"))) {
			String logined = CookieUtils.getCookie(request, "LOGINED");
			if (StringUtils.isBlank(logined) || "false".equals(logined)) {
				CookieUtils.setCookie(response, "LOGINED", "true");
			} else if (StringUtils.equals(logined, "true")) {
				UserUtils.getSubject().logout();
				return "redirect:" + adminPath + "/login";
			}
		}

		// 如果是手机登录，则返回JSON字符串
		if (principal.isMobileLogin()) {
			if (request.getParameter("login") != null) {
				return renderString(response, principal);
			}
			if (request.getParameter("index") != null) {
				return "modules/sys/sysIndex";
			}
			return "redirect:" + adminPath + "/login";
		}

		return "modules/sys/sysIndex";
	}

	/**
	 * 获取主题方案
	 */
	@RequestMapping(value = "/theme/{theme}")
	public String getThemeInCookie(@PathVariable String theme, HttpServletRequest request,
			HttpServletResponse response) {
		if (StringUtils.isNotBlank(theme)) {
			CookieUtils.setCookie(response, "theme", theme);
		} else {
			theme = CookieUtils.getCookie(request, "theme");
		}
		return "redirect:" + request.getParameter("url");
	}

	/**
	 * 判断是否需要验证码登录
	 * 
	 * @param useruame 用户名
	 * @param isFail 计数加1
	 * @param clean 计数清零
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static boolean isValidateCodeLogin(String useruame, boolean isFail, boolean clean) {
		Map<String, Integer> loginFailMap = (Map<String, Integer>) CacheUtils.get("loginFailMap");
		if (loginFailMap == null) {
			loginFailMap = Maps.newHashMap();
			CacheUtils.put("loginFailMap", loginFailMap);
		}
		Integer loginFailNum = loginFailMap.get(useruame);
		if (loginFailNum == null) {
			loginFailNum = 0;
		}
		if (isFail) {
			loginFailNum++;
			loginFailMap.put(useruame, loginFailNum);
		}
		if (clean) {
			loginFailMap.remove(useruame);
		}
		return loginFailNum >= 3;
	}
	
}
